Αυτές τις μέρες γράφω κώδικα που έχει να κάνει με την προγραμματιστική δημιουργία ενός πακέτου για τα Integration Services του SQL Server και μου έτυχε το εξής ενδιαφέρον πρόβλημα (έτσι κουβέντα να γίνεται):
Ας ξεκινήσουμε με την πρώτη έκδοση του κώδικα την οποία δοκίμασα αρχικά:
' Select and map destination columns
For Each virtualInputColumn As IDTSVirtualInputColumn100 In destinationVirtualInputColumns
' Select column, and retain new input column
Dim inputColumn As IDTSInputColumn100 = sqlServerDestInstance.SetUsageType(destinationInput.ID, destinationVirtualInput, virtualInputColumn.LineageID, DTSUsageType.UT_READONLY)
' Find external column
Dim externalColumn As IDTSExternalMetadataColumn100 = Nothing
For Each di As IDTSExternalMetadataColumn100 In destinationInput.ExternalMetadataColumnCollection
If di.Name = inputColumn.Name Then
externalColumn = di
Exit For
End If
Next
' Map input column to external column
If externalColumn IsNot Nothing Then
Debug.WriteLine(externalColumn.Name)
sqlServerDestInstance.MapInputColumn(destinationInput.ID, inputColumn.ID, externalColumn.ID)
Else
Debug.WriteLine("Not found: " & virtualInputColumn.Name)
End If
Next virtualInputColumn
Μην τρομάξετε και σας χάσω, ο κώδικας είναι απλός. Έχουμε μια σειρά από input columns και θέλουμε να τα κάνουμε map σε output columns. Μέσα στα input columns είναι πολλά που δεν μας κάνουν οπότε η λογική πάει ως εξής. Έχουμε δύο collections, το destinationVirtualInputColumns και το ExternalMetadataColumnCollection. Παίρνουμε ένα-ένα τα input columns και ψάχνουμε αν υπάρχουν στο ExternalMetadataColumnCollection ώστε στη συνέχεια να κάνουμε MapInputColumn. Το ExternalMetadataColumnCollection είναι ένα χαζό-collection από interfaces IDTSExternalMetadataColumn100, μιλάμε για COM και δεν έχει εξυπνάδες τύπου "Contains". Έχει όμως μια εξυπνάδα που τη χρησιμοποίησα για να κάνω τη δεύτερη έκδοση του snippet:
' Select and map destination columns
For Each virtualInputColumn As IDTSVirtualInputColumn100 In destinationVirtualInputColumns
' Select column, and retain new input column
Dim inputColumn As IDTSInputColumn100 = sqlServerDestInstance.SetUsageType(destinationInput.ID, destinationVirtualInput, virtualInputColumn.LineageID, DTSUsageType.UT_READONLY)
' Find external column by name
Dim externalColumn As IDTSExternalMetadataColumn100 = Nothing
Try
externalColumn = destinationInput.ExternalMetadataColumnCollection(inputColumn.Name)
Catch ex As System.Runtime.InteropServices.COMException
'Bummer! Column not found...
End Try
' Map input column to external column
If externalColumn IsNot Nothing Then
Debug.WriteLine(externalColumn.Name)
sqlServerDestInstance.MapInputColumn(destinationInput.ID, inputColumn.ID, externalColumn.ID)
Else
Debug.WriteLine("Not found: " & virtualInputColumn.Name)
End If
Next virtualInputColumn
Προσέξτε το Try/Catch. Μπορώ να πάρω reference χρησιμοποιώντας το Item default property ωστόσο αν δεν υπάρχει αυτό που ψάχνω έχω exception. Δεν μπορώ να πω ότι με ενθουσιάζει προγραμματιστικά αυτός ο τρόπος, οπότε είπα να δοκιμάσω και με LINQ, περισσότερο από περιέργεια καθώς ήξερα ότι από πλευράς performance δεν θα γούρλωνα τα μάτια:
Dim externalColumns = destinationInput.ExternalMetadataColumnCollection.Cast(Of IDTSExternalMetadataColumn100)()
' Select and map destination columns
For Each virtualInputColumn As IDTSVirtualInputColumn100 In destinationVirtualInputColumns
' Select column, and retain new input column
Dim inputColumn As IDTSInputColumn100 = sqlServerDestInstance.SetUsageType(destinationInput.ID, destinationVirtualInput, virtualInputColumn.LineageID, DTSUsageType.UT_READONLY)
' Find external column by name
Dim externalColumn = externalColumns _
.SingleOrDefault(Function(c) c.Name = inputColumn.Name)
' Map input column to external column
If externalColumn IsNot Nothing Then
Debug.WriteLine(externalColumn.Name)
sqlServerDestInstance.MapInputColumn(destinationInput.ID, inputColumn.ID, externalColumn.ID)
Else
Debug.WriteLine("Not found: " & virtualInputColumn.Name)
End If
Next virtualInputColumn
Πιο κομψός κώδικας σε σχέση με τις δύο προηγούμενες δοκιμές. Κράτησα για το τέλος το θέμα του performance. Με ένα stopwatch μέτρησα και βρήκα τα παρακάτω:
1η έκδοση: 01 min και 05.87 sec
2η έκδοση: 00 min και 03.48 sec
3η έκδοση: 01 min και 37.79 sec
Ουφ! Φτάσαμε στο τέλος. Το ερώτημα είναι... πώς λένε τον οδηγό; Χα, όχι. Ποιόν κώδικα κρατάς και γιατί;
Vir prudens non contra ventum mingit